/*
 *  WilTracker.cpp
 *  Wilson
 *
 *  Created by Sebastian Orfino on 8/12/11.
 *  Copyright 2011 Lbs3 Software. All rights reserved.
 *
 */

#include "VCPlugInHeaders.h"

//Interface includes:
#include "IUIColorUtils.h"
#include "IUserInfo.h"
#include "PreferenceUtils.h"
#include "INewPageItemCmdData.h"
#include "IEvent.h"
#include "IControlView.h"
#include "ILayoutControlViewHelper.h"
#include "ILayoutControlData.h"
#include "ILayoutCmdData.h"
#include "IDataBase.h"
#include "IDocument.h"
#include "ISpread.h"
#include "IPanorama.h"
#include "ILayerUtils.h"
//#include "ISnapPrefsData.h"
#include "IWorkspace.h"
#include "IK2ServiceRegistry.h"
#include "IK2ServiceProvider.h"
#include "IImageWriteFormatInfo.h"
#include "ILayoutSelectionSuite.h"
#include "ISelectionManager.h"
#include "ISelectionUtils.h"
#include "IGeometryFacade.h"
#include "IImageStreamManager.h"
#include "IImageWriteFormat.h"
#include "IImageStream.h"
#include "IImageAttributes.h"
#include "ICreateCacheImageStreamData.h"

// General includes
#include "SDKFileHelper.h"
#include "JPEGFilterID.h"
#include "SplineID.h"
#include "ShuksanID.h"
#include "LayoutUIID.h"
#include "ILayoutUIUtils.h"
#include "IPathUtils.h"
#include "IPageItemUtils.h"
#include "IPasteboardUtils.h"
#include "PersistUtils.h"
#include "CAlert.h"
#include "CmdUtils.h"
#include "Trace.h"
#include "SelectUtils.h"
#include "ImageID.h"
#include "CPathCreationTracker.h"
#include "ITextWrapFacade.h"
#include "ErrorUtils.h"
#include "IInterfaceColors.h"
#include "IInCopyUIColors.h"

//Project includes
#include "WilID.h"
#include "IWilNoteData.h"
#include "preparar_nota_nueva.h"
#include "csxs_facade.h"
#include "mi_layer.h"
#include "color_nota.h"
#include "abrir_modal.h"
#include "xmp_facade.h"
#include "SDKLayoutHelper.h"

//sdk includes
#include "ITool.h"
#include "IToolBoxUtils.h"
#include "IXPAttributeFacade.h"
#include "SnpGraphicHelper.h"
#include "ISwatchUtils.h"
#include "APath.h"
//#include "IPathGeometry.h"
//#include "SnapshotUtilsEx.h"
//#include "IHierarchy.h"
//#include "IPathUtils.h"
//#include "StreamUtil.h"

#include "snapshot_helper.h"

#include "boost/shared_ptr.hpp"
#include "adobe/unicode.hpp"

#include <sstream>
#include <iomanip>

using namespace std;
using namespace eventos;
using namespace wilson;

class WilTracker: public CPathCreationTracker {

public:
	WilTracker(IPMUnknown * ipu) : CPathCreationTracker(ipu) {}
	~WilTracker() { }
	
	virtual void ProcessAdditionalCreationCommands (const UIDRef& newItem, const UIDRef& parent, const PMPointList& points, IPlaceBehavior::eAfterPlace afterPlace);
	/** Override this method to make the cursor show dynamic metric info. */
	virtual CursorOptions GetCursorOption(void) const;
	
	/** Crea mi page item */
	virtual UIDRef CreatePageItem (const UIDRef& parent, const PMPointList& points, const IEvent& theEvent, IPlaceBehavior::eAfterPlace *afterPlace = nil);
	
	/** lo sobrecargo para que no quede seleccionado */
	virtual void  ProcessAdditionalSelectionCommands (const UIDRef& newItem);
	
	
	virtual void AddToHierarchy (const UIDRef& parent, const UIDRef& newItem);
private:
	
	UIDRef newItem; //el pageitem (marcador) que se ha creado.
	ColorArray newItemColor; ///el color del marcador (el rectangulo) que estoy creando.
	
	/** Pone la herramienta de seleccion activa */
	void ActivarSelectionTool() const;
	
	/** Pinta y taguea el rectangulo creado (el marcador) */
	void AdornarItemCreado() ;
		
	/** Deberia construir y enviar el evento de creacion del comentario a la extension */
	void EnviarEventoAExtension();
	
	/** El documento donde se creo el marcador */
	InterfacePtr<IDocument> documento;
	
	/** luego se crear la caja con el marcador en el documente se vuelve al layer que estaba activo antes por el usuario.
	 Esta variable es ese layer
	 */
	UIDRef layerGuardado;

	void GuardarLayerActivo();
	void RestaurarLayerActivo() const;
	
};

CREATE_PMINTERFACE(WilTracker, kWilTrackerImpl);

void WilTracker::AddToHierarchy (const UIDRef& parent, const UIDRef& _newItem)
{
	
	CPathCreationTracker::AddToHierarchy(parent,_newItem);
	/*
	//lo coloco en el layer especial para las notas.
	InterfacePtr<ISpread> spread(Utils<IPasteboardUtils>()->QuerySpread(fControlView,fStartPnt));
	if (!spread) return;
	
	GuardarLayerActivo();
	
	mi_layer layer(spread);
	CPathCreationTracker::AddToHierarchy(layer.content_layer(),newItem);
	*/
	
	
}

void WilTracker::GuardarLayerActivo()
{

	InterfacePtr<IDocumentLayer> doc_layer(Utils<ILayerUtils>()->QueryDocumentActiveLayer(documento),UseDefaultIID());
	if (doc_layer)
		layerGuardado = ::GetUIDRef(doc_layer);

}

void WilTracker::RestaurarLayerActivo() const
{

	do {
		BREAK_IF(layerGuardado == UIDRef::gNull);
		
		InterfacePtr<ICommand> setActiveLayer(CmdUtils::CreateCommand(kSetActiveLayerCmdBoss));
		BREAK_IF(!setActiveLayer);
		setActiveLayer->SetItemList(UIDList(layerGuardado));

		InterfacePtr<ILayoutCmdData> setActiveLayerCmdData(setActiveLayer, UseDefaultIID());
		BREAK_IF(!setActiveLayerCmdData)
		
		InterfacePtr<ILayoutControlData> layoutControlData(fControlView, UseDefaultIID());
		BREAK_IF(!layoutControlData)
		setActiveLayerCmdData->Set(::GetUIDRef(documento), layoutControlData);

		ErrorCode err = CmdUtils::ProcessCommand(setActiveLayer);
		
		TRACE_IF(err != kSuccess,"no se pudo restaurar el layer activo");
	}
	while(false);
}

void  WilTracker::ProcessAdditionalSelectionCommands (const UIDRef& )
{
	RestaurarLayerActivo();
}

UIDRef WilTracker::CreatePageItem (const UIDRef& parent, const PMPointList& points, const IEvent& theEvent, IPlaceBehavior::eAfterPlace *afterPlace)
{

	//creo el page item. Notar que es kWilNoteSplineBoss, es decir, un page item que es propietario de la extension.
	//Si quieren abrir el documento sin esta extension les va a dar un alerta. todo: ver como personalizar el alerta, se puede.
	UIDRef result(nil, kInvalidUID);	
	do {
		InterfacePtr<ICommand> newPageItem (  CmdUtils::CreateCommand(kNewPageItemCmdBoss));
		BREAK_IF(!newPageItem);
		InterfacePtr<INewPageItemCmdData> data(newPageItem, IID_INEWPAGEITEMCMDDATA);
		BREAK_IF(!data);
		data->Set(parent.GetDataBase (), kWilNoteSplineBoss, this->IsGraphicFrame() ? INewPageItemCmdData::kGraphicFrameAttributes : 
				  INewPageItemCmdData::kDefaultGraphicAttributes);
		data->SetObjectStyleApplication(INewPageItemCmdData::kNeverApplyObjectStyle);
		
		ErrorCode err = CmdUtils::ProcessCommand(newPageItem);
		BREAK_IF(err!=kSuccess);
		
		const UIDList* itemList = newPageItem->GetItemList();
		
		if(itemList && itemList->Length() > 0)
			result = itemList->GetRef(0);
		
		if (afterPlace)
			*afterPlace = IPlaceBehavior::kOldBehavior;
		
		newItem = result;
		IDataBase * db= newItem.GetDataBase();
		documento = InterfacePtr<IDocument>(db,db->GetRootUID(),UseDefaultIID());
	} while(false);
	
	return result;
}

void WilTracker::ProcessAdditionalCreationCommands (const UIDRef& _newItem, const UIDRef& parent, const PMPointList& points, IPlaceBehavior::eAfterPlace afterPlace)
{
	CPathCreationTracker::ProcessAdditionalCreationCommands(newItem,parent,points,afterPlace);
	TRACE("");

	if (ErrorUtils::PMGetGlobalErrorCode()==kSuccess)
	{
		AdornarItemCreado();
	}
	
	if (ErrorUtils::PMGetGlobalErrorCode()==kSuccess)
		EnviarEventoAExtension();
	
	//RestaurarLayerActivo();
	
	//finalmente activo la selection tool.
	ActivarSelectionTool();
	
	//newItem = kInvalidUIDRef; 
	// listo, seteo esto a cero. no hacer esto porque da EXEC_BAD_ACCESS. no se por que.
	/* Debe ser por los UIDList(newItem) que hago y paso como parametro a algunas interfaces y/o comandos que se aplican una vez
	 que yo dejo de intervenir. Aunque no se, porque UIDList() deberia hacer una copia o no?
	 */
}

void WilTracker::EnviarEventoAExtension()
{
	InterfacePtr<IWilNoteData> datosNota(newItem,UseDefaultIID());
	if (datosNota) {
			
		datosNota->touch(); //esto para que el ID lo persista.
		
		do {
			
			UIDList itemList(newItem);
			PMRect clippingBounds = Utils<Facade::IGeometryFacade>()->GetItemsBounds(itemList, Transform::SpreadCoordinates(), Geometry::OuterStrokeBounds());
			InterfacePtr<ISpread> spread(Utils<IPasteboardUtils>()->QuerySpread(fControlView,fStartPnt));
			BREAK_IF(!spread);
			
			snapshot_helper helper(::GetUIDRef(spread));
			//le saco una foto a la zona donde el usuario hizo la nota. esta foto se usa como referencia en la paleta.
			std::string foto = helper.shoot(clippingBounds);
			
			
			//el userInfo para conocer algunas prefs del usuario.
			InterfacePtr<IUserInfo> userInfo(::QuerySessionPreferences(IID_IUSERINFO),UseDefaultIID());
			BREAK_IF(!userInfo);
			PMString uname = userInfo->GetUserName();
			
			preparar_nota_nueva param;
			param.id_payload() = datosNota->uid().str();
		
			adobe::to_utf8(uname.begin(),uname.end(),back_inserter(param.creador()));

			eventos::abrir_modal * abrir_el_modal = new eventos::abrir_modal();
			abrir_el_modal->pasar_parametros(param);
			
			conversacion_ptr ptr(abrir_el_modal);			
			iniciador initer = conversaciones::preparar_nueva(ptr);
			initer.iniciar();
			char color_en_hexa[6];
			int r = ToDouble(newItemColor[0]) * 255;
			int g = ToDouble(newItemColor[1]) * 255;
			int b = ToDouble(newItemColor[2]) * 255;
			sprintf(color_en_hexa,"#%02X%02X%02X",r,g,b);//ToDouble(newItemColor[0]) * 255U);//,ToDouble(newItemColor[1]) * 255U,ToDouble(newItemColor[2]) * 255U);
			
			
			
			xmp::info_nota_t info = { param.id_payload(), 
									  foto,
									  param.creador(),
									  param.timestamp(),
									  color_en_hexa
			};
			
			xmp::wilson_metadata metadata(::GetUIDRef(documento));
			metadata.crear_nota(info);
			
			//metadata.dump();
			
			
     	}while(kFalse);
    	
	}
	
}
/*
void WilTracker::ActualizarDatosEnLaNota(const UIDRef& newItem, snapshot_ptr snapshot)
{
	
	
	do {
		InterfacePtr<IWilNoteData> datosNota(newItem,UseDefaultIID());
		ClassID classId = newItem.GetDataBase()->GetClass(newItem.GetUID()); 
		if (datosNota) {
			WideString com("comentario..");
			datosNota->Comentario(com);
			
			
			WilBase64XferBytes buffer;
			InterfacePtr<IPMStream> base64Stream(StreamUtil::CreateMemoryStreamWrite(&buffer));
			
			
			//InterfacePtr<IPMStream> base64Stream(CreateObject2<IPMStream>(kWilBase64StreamBoss, IID_IPMSTREAM));
			if (!base64Stream) break;
			if (!snapshot) break;
			
			ErrorCode err = snapshot->ExportImageToPNG(base64Stream);
			if (err != kSuccess) break;
			
			
			WideString miniImagen(buffer.GetBuffer().c_str());
			datosNota->MiniImagenBase64(miniImagen);
		}
	
	} while(kFalse);
	
    
	
}*/

void WilTracker:: AdornarItemCreado()
{
	UIDList items(newItem);
	
	//el userInfo para conocer algunas prefs del usuario.
	InterfacePtr<IUserInfo> userInfo(::QuerySessionPreferences(IID_IUSERINFO),UseDefaultIID());

	UID miColor = kInvalidUID;
	newItemColor.clear();
	if (userInfo)
	{
		//veo que color tiene el usuario seteado para la sesion (menu File->User..)
		int32 index = userInfo->GetUserColorIndex();
		
		//convierto este color a un swatch.
		InterfacePtr<IInCopyUIColors> uiColors(::GetExecutionContextSession(),UseDefaultIID());
		if (uiColors) {
			RealAGMColor rgb = uiColors->GetColorValue(index);
			newItemColor.push_back(rgb.red);
			newItemColor.push_back(rgb.green);
			newItemColor.push_back(rgb.blue);
		}
	}
	else { //si no puedo obtener el color del usuario armo uno generico.
		newItemColor.push_back(1.0); 
		newItemColor.push_back(0.0);
		newItemColor.push_back(0.0); 
	}
	//	miColor = graphicHelper.GetNamedSwatch("C=15 M=100 Y=100 K=0", newItem.GetDataBase());
	
	color_nota color; 
	//el swatch se agrega al documento actual. Ver doc de color_nota.
	color.crear(newItemColor);
	miColor = color.swatch_uid();
	
	//con este helper le asigno los atributos a la caja de la nota.
	SnpGraphicHelper graphicHelper(newItem);
	
	//un trazo de 5 pt //todo: es mucho ?
	graphicHelper.AddStrokeWeight(5.0);
	graphicHelper.AddStrokeRendering(miColor);
	
	graphicHelper.AddFillRendering(miColor);
	graphicHelper.ApplyAttributes();
									   
	//le pongo la transparencia.
	Utils<IXPAttributeFacade>()->SetOpacity(items,30.0);

	//me aseguro que la caja no produzca ningun efecto de wrapping del texto.
	Utils<Facade::ITextWrapFacade>()->SetMode(items,IStandOff::kNone);
	
}

void WilTracker::ActivarSelectionTool() const 
{
	do {
		
		//despues de crear el item quiero que se active la herramienta de seleccion automaticamente.
		InterfacePtr<ITool> iSelectionTool(Utils<IToolBoxUtils>()->QueryTool(kPointerToolBoss));
		BREAK_IF(!iSelectionTool);
		Utils<IToolBoxUtils>()->SetActiveTool(iSelectionTool);
		
	} while(false);
}

CPathCreationTracker::CursorOptions WilTracker::GetCursorOption(void) const 
{
	return CPathCreationTracker::kShowLineLength;
}

